from flask import Flask, render_template, request, jsonify, session, redirect, url_for, Response
from flask_cors import CORS
import hashlib
import qrcode
import base64
import io
import json
import os
from clients import ClientFactory
from services import VirtualCloudService

app = Flask(__name__)
app.secret_key = 'your-secret-key-here'  # 请更改为安全的密钥
CORS(app)

# 获取默认的网盘客户端类型
DEFAULT_CLIENT_TYPE = 'cloud189'

# 缓存文件路径
CACHE_FILE = 'cloud189_cache.json'

def get_client(client_type=None):
    """获取网盘客户端实例"""
    if client_type is None:
        client_type = DEFAULT_CLIENT_TYPE
    return ClientFactory.get_client(client_type)

def save_cache(data):
    """保存缓存到本地文件"""
    try:
        with open(CACHE_FILE, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"保存缓存失败: {e}")

def load_cache():
    """从本地文件加载缓存"""
    try:
        if os.path.exists(CACHE_FILE):
            with open(CACHE_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
    except Exception as e:
        print(f"加载缓存失败: {e}")
    return {}

def clear_cache():
    """清除缓存文件"""
    try:
        if os.path.exists(CACHE_FILE):
            os.remove(CACHE_FILE)
    except Exception as e:
        print(f"清除缓存失败: {e}")

# 启动时加载缓存
cache_data = load_cache()
cloud_client = get_client()
if 'token_info' in cache_data:
    cloud_client.token_info = cache_data['token_info']

# 初始化虚拟网盘服务
virtual_cloud = VirtualCloudService()

@app.route('/')
def index():
    """主页"""
    return render_template('index.html')

@app.route('/virtual')
def virtual_cloud_page():
    """虚拟网盘页面"""
    return render_template('virtual_cloud.html')

@app.route('/api/get_qr_code')
def get_qr_code():
    """获取登录二维码"""
    client = get_client()
    uuid = client.get_qr_uuid()
    if uuid:
        # 生成二维码
        qr = qrcode.QRCode(version=1, box_size=10, border=5)
        qr.add_data(uuid)
        qr.make(fit=True)
        
        img = qr.make_image(fill_color="black", back_color="white")
        img_buffer = io.BytesIO()
        img.save(img_buffer, format='PNG')
        img_buffer.seek(0)
        
        img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
        
        # 保存UUID到session
        session['temp_uuid'] = uuid
        
        return jsonify({
            'success': True,
            'uuid': uuid,
            'qr_code': f'data:image/png;base64,{img_base64}',
            'login_url': uuid
        })
    
    return jsonify({'success': False, 'message': '获取二维码失败'})

@app.route('/api/check_login_status', methods=['GET'])
def check_login_status():
    """检查当前登录状态"""
    client = get_client()
    if client.is_logged_in:
        return jsonify({
            'success': True,
            'logged_in': True,
            'message': '已登录',
            'token_info': client.token_info
        })
    else:
        return jsonify({
            'success': True,
            'logged_in': False,
            'message': '未登录'
        })

@app.route('/api/check_login', methods=['POST'])
def check_login():
    """检查登录状态"""
    data = request.get_json()
    uuid = data.get('uuid')
    
    if not uuid:
        return jsonify({'success': False, 'message': '缺少UUID参数'})
    
    client = get_client()
    # 检查二维码登录状态
    access_token = client.check_qr_login(uuid)
    if access_token:
        # 使用AccessToken完成登录
        if client.login_with_token(access_token):
            # 保存登录信息到缓存
            cache_data = {
                'token_info': client.token_info
            }
            save_cache(cache_data)
            
            return jsonify({
                'success': True, 
                'message': '登录成功',
                'token_info': client.token_info
            })
        else:
            return jsonify({'success': False, 'message': '登录失败'})
    else:
        return jsonify({'success': False, 'message': '二维码未扫描或已过期'})

@app.route('/api/file_list')
def file_list():
    """获取文件列表"""
    client = get_client()
    if not client.is_logged_in:
        return jsonify({'success': False, 'message': '未登录'})
    
    folder_id = request.args.get('folder_id', '-11')
    is_family = request.args.get('is_family', 'false').lower() == 'true'
    
    files = client.get_file_list(folder_id, is_family)
    if files:
        return jsonify({'success': True, 'data': files})
    
    return jsonify({'success': False, 'message': '获取文件列表失败'})

@app.route('/api/file_info/<file_id>')
def file_info(file_id):
    """获取文件详细信息"""
    client = get_client()
    if not client.is_logged_in:
        return jsonify({'success': False, 'message': '未登录'})
    
    is_family = request.args.get('is_family', 'false').lower() == 'true'
    
    file_detail = client.get_file_info(file_id, is_family)
    if file_detail:
        return jsonify({'success': True, 'data': file_detail})
    
    return jsonify({'success': False, 'message': '获取文件信息失败'})

@app.route('/api/logout', methods=['POST'])
def logout():
    """登出"""
    client = get_client()
    client.token_info = None
    clear_cache()  # 清除本地缓存
    return jsonify({'success': True, 'message': '已退出登录'})

@app.route('/api/upload_check', methods=['POST'])
def upload_check():
    """检查文件是否可以秒传"""
    try:
        data = request.get_json()
        file_name = data.get('fileName')
        file_size = data.get('fileSize')
        file_md5 = data.get('fileMd5')
        parent_id = data.get('parentId', '-11')
        is_family = data.get('isFamily', False)
        
        print(f"[上传检查] 文件名: {file_name}, 大小: {file_size}, MD5: {file_md5}, 父目录: {parent_id}, 家庭云: {is_family}")
        
        if not all([file_name, file_size, file_md5]):
            print(f"[缺少必要参数] 文件名: {file_name}, 大小: {file_size}, MD5: {file_md5}, 父目录: {parent_id}, 家庭云: {is_family}")
            return jsonify({'success': False, 'message': '缺少必要参数'})
        
        client = get_client()
        # 调用创建上传会话接口检查是否可以秒传
        upload_info = client.create_upload_session(parent_id, file_md5, file_name, str(file_size), is_family)
        
        if upload_info and upload_info.get('fileDataExists') == 1:
            print(f"[上传检查] 文件可以秒传: {file_name}")
            return jsonify({
                'success': True, 
                'canRapidUpload': True,
                'uploadInfo': upload_info,
                'message': '文件已存在，可以秒传'
            })
        else:
            print(f"[上传检查] 文件需要正常上传: {file_name}")
            return jsonify({
                'success': True, 
                'canRapidUpload': False,
                'uploadInfo': upload_info,
                'message': '文件需要正常上传'
            })
            
    except Exception as e:
        print(f"[上传检查错误] {str(e)}")
        return jsonify({'success': False, 'message': f'检查上传失败: {str(e)}'})

@app.route('/api/upload_rapid', methods=['POST'])
def upload_rapid():
    """执行秒传"""
    try:
        data = request.get_json()
        upload_info = data.get('uploadInfo')
        is_family = data.get('isFamily', False)
        
        print(f"[秒传执行] 上传信息: {upload_info}, 家庭云: {is_family}")
        
        if not upload_info:
            return jsonify({'success': False, 'message': '缺少上传信息'})
        
        client = get_client()
        # 提交秒传
        result = client.commit_upload(upload_info.get('fileCommitUrl'), upload_info.get('uploadFileId'), is_family, True)
        
        if result:
            print(f"[秒传成功] 文件: {result.get('name', '未知')}")
            return jsonify({'success': True, 'data': result, 'message': '秒传成功'})
        else:
            print(f"[秒传失败] 提交失败")
            return jsonify({'success': False, 'message': '秒传失败'})
            
    except Exception as e:
        print(f"[秒传错误] {str(e)}")
        return jsonify({'success': False, 'message': f'秒传失败: {str(e)}'})

@app.route('/api/upload', methods=['POST'])
def upload_file():
    """上传文件"""
    try:
        if 'file' not in request.files:
            return jsonify({'success': False, 'message': '没有选择文件'})
        
        file = request.files['file']
        parent_id = request.form.get('parentId', '-11')
        is_family = request.form.get('isFamily', 'false').lower() == 'true'
        file_md5 = request.form.get('fileMd5')  # 从前端获取已计算的MD5
        
        if file.filename == '':
            return jsonify({'success': False, 'message': '文件名为空'})
        
        print(f"[文件上传] 开始上传文件: {file.filename}, 父目录: {parent_id}, 家庭云: {is_family}, MD5: {file_md5}")
        
        # 读取文件内容（只读取一次）
        file_content = file.read()
        file_size = len(file_content)
        
        # 如果前端没有提供MD5，则在服务器端计算（兼容性处理）
        if not file_md5:
            print(f"[文件上传] 前端未提供MD5，服务器端计算...")
            file_md5 = hashlib.md5(file_content).hexdigest()
        
        print(f"[文件上传] 文件信息 - 大小: {file_size}, MD5: {file_md5}")
        
        client = get_client()
        # 创建上传会话
        upload_info = client.create_upload_session(parent_id, file_md5, file.filename, str(file_size), is_family)
        
        if not upload_info:
            return jsonify({'success': False, 'message': '创建上传会话失败'})
        
        print(f"[文件上传] 上传会话创建成功: {upload_info}")
        
        # 检查是否可以秒传
        if upload_info.get('fileDataExists') == 1:
            print(f"[文件上传] 检测到可以秒传，直接提交")
            result = client.commit_upload(upload_info.get('fileCommitUrl'), upload_info.get('uploadFileId'), is_family, True)
            if result:
                return jsonify({'success': True, 'data': result, 'message': '秒传成功'})
        
        # 正常上传文件数据
        print(f"[文件上传] 开始上传文件数据到: {upload_info.get('fileUploadUrl')}")
        upload_result = client.upload_file_data(upload_info, file_content, is_family)
        
        if upload_result:
            print(f"[文件上传] 文件数据上传成功，开始提交")
            # 提交上传
            result = client.commit_upload(upload_info.get('fileCommitUrl'), upload_info.get('uploadFileId'), is_family, True)
            if result:
                print(f"[文件上传] 上传完成: {result.get('name', '未知')}")
                return jsonify({'success': True, 'data': result, 'message': '上传成功'})
        
        return jsonify({'success': False, 'message': '上传失败'})
        
    except Exception as e:
        print(f"[文件上传错误] {str(e)}")
        return jsonify({'success': False, 'message': f'上传失败: {str(e)}'})

@app.route('/api/download/<file_id>')
def download_file(file_id):
    """下载文件"""
    try:
        is_family = request.args.get('isFamily', 'false').lower() == 'true'
        
        print(f"[文件下载] 开始下载文件: {file_id}, 家庭云: {is_family}")
        
        client = get_client()
        # 获取下载链接
        download_url = client.get_download_url(file_id, is_family)
        
        if download_url:
            print(f"[文件下载] 获取下载链接成功: {download_url}")
            
            # 流式下载文件
            def generate():
                try:
                    headers = {
                        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
                    }
                    response = client.session.get(download_url, headers=headers, stream=True)
                    
                    if response.status_code == 200:
                        for chunk in response.iter_content(chunk_size=8192):
                            if chunk:
                                yield chunk
                    else:
                        print(f"[文件下载] 下载失败，状态码: {response.status_code}")
                except Exception as e:
                    print(f"[文件下载] 流式下载错误: {str(e)}")
            
            # 获取文件信息以设置正确的响应头
            try:
                head_response = client.session.head(download_url)
                content_length = head_response.headers.get('Content-Length')
                content_type = head_response.headers.get('Content-Type', 'application/octet-stream')
                
                response_headers = {
                    'Content-Type': content_type,
                    'Content-Disposition': f'attachment; filename="file_{file_id}"'
                }
                
                if content_length:
                    response_headers['Content-Length'] = content_length
                    
                return Response(generate(), headers=response_headers)
                
            except Exception as e:
                print(f"[文件下载] 获取文件信息失败: {str(e)}")
                # 如果获取文件信息失败，仍然尝试下载
                return Response(generate(), headers={
                    'Content-Type': 'application/octet-stream',
                    'Content-Disposition': f'attachment; filename="file_{file_id}"'
                })
        else:
            print(f"[文件下载] 获取下载链接失败")
            return jsonify({'success': False, 'message': '获取下载链接失败'})
            
    except Exception as e:
        print(f"[文件下载错误] {str(e)}")
        return jsonify({'success': False, 'message': f'下载失败: {str(e)}'})

@app.route('/api/clients')
def get_available_clients():
    """获取可用的客户端列表"""
    try:
        clients = ClientFactory.get_available_clients()
        return jsonify({'success': True, 'clients': clients})
    except Exception as e:
        return jsonify({'success': False, 'message': f'获取客户端列表失败: {str(e)}'})

# ==================== 虚拟网盘API ====================

@app.route('/api/virtual/check_rapid_upload', methods=['POST'])
def virtual_check_rapid_upload():
    """检查文件是否可以秒传"""
    try:
        data = request.get_json()
        file_md5 = data.get('fileMd5')
        file_name = data.get('fileName')
        file_size = data.get('fileSize')
        cloud_type = data.get('cloudType', 'cloud189')
        parent_id = data.get('parentId', '-11')
        is_family = data.get('isFamily', False)
        
        if not all([file_md5, file_name, file_size]):
            return jsonify({'success': False, 'message': '缺少必要参数'})
        
        # 检查虚拟网盘中是否已存在
        existing_file = virtual_cloud.get_file_info(file_md5)
        virtual_exists = existing_file is not None
        
        # 检查云盘是否可以秒传
        client = get_client(cloud_type)
        if not client.is_logged_in:
            return jsonify({
                'success': False, 
                'message': '请先登录云盘账户'
            })
        
        try:
            upload_info = client.create_upload_session(
                parent_id, file_md5, file_name, str(file_size), is_family
            )
            cloud_rapid = upload_info.get('rapidUpload', False)
        except Exception as e:
            cloud_rapid = False
            print(f"检查云盘秒传失败: {str(e)}")
        
        return jsonify({
            'success': True,
            'virtual_exists': virtual_exists,
            'cloud_rapid': cloud_rapid,
            'file_info': existing_file
        })
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'检查失败: {str(e)}'})

@app.route('/api/virtual/add_file', methods=['POST'])
def virtual_add_file():
    """添加文件到虚拟网盘"""
    try:
        if 'file' in request.files:
            # 通过文件内容添加
            file = request.files['file']
            
            if file.filename == '':
                return jsonify({'success': False, 'message': '文件名为空'})
            
            file_content = file.read()
            tags = request.form.get('tags', '')
            description = request.form.get('description', '')
            
            result = virtual_cloud.add_file_by_content(
                file_content, file.filename, tags, description
            )
            
        else:
            # 通过MD5信息添加
            data = request.get_json()
            file_md5 = data.get('fileMd5')
            original_name = data.get('fileName')
            file_size = data.get('fileSize')
            tags = data.get('tags', '')
            description = data.get('description', '')
            
            if not all([file_md5, original_name, file_size]):
                return jsonify({'success': False, 'message': '缺少必要参数'})
            
            result = virtual_cloud.add_file_by_md5(
                file_md5, original_name, int(file_size), tags, description
            )
        
        return jsonify(result)
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'添加文件失败: {str(e)}'})

@app.route('/api/virtual/search', methods=['GET'])
def virtual_search_files():
    """搜索虚拟网盘文件"""
    try:
        query = request.args.get('q', '')
        search_type = request.args.get('type', 'name')  # name, tags, md5
        
        if not query:
            return jsonify({'success': False, 'message': '搜索关键词不能为空'})
        
        results = virtual_cloud.search_files(query, search_type)
        
        return jsonify({
            'success': True,
            'results': results,
            'count': len(results)
        })
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'搜索失败: {str(e)}'})

@app.route('/api/virtual/file/<file_md5>')
def virtual_get_file_info(file_md5):
    """获取文件详细信息"""
    try:
        file_info = virtual_cloud.get_file_info(file_md5)
        
        if file_info:
            return jsonify({'success': True, 'file_info': file_info})
        else:
            return jsonify({'success': False, 'message': '文件不存在'})
            
    except Exception as e:
        return jsonify({'success': False, 'message': f'获取文件信息失败: {str(e)}'})

@app.route('/api/virtual/check_cloud_status/<file_md5>')
def virtual_check_cloud_status(file_md5):
    """检查云盘文件状态"""
    try:
        cloud_type = request.args.get('cloudType', 'cloud189')
        parent_id = request.args.get('parentId', '-11')
        is_family = request.args.get('isFamily', 'false').lower() == 'true'
        
        # 检查云盘文件状态
        cloud_status = virtual_cloud.check_cloud_file_exists(file_md5, cloud_type, parent_id, is_family)
        
        # 获取文件信息
        file_info = virtual_cloud.get_file_info(file_md5)
        if not file_info:
            return jsonify({'success': False, 'message': '文件信息不存在'})
        
        return jsonify({
            'success': True,
            'cloud_status': cloud_status,
            'file_info': file_info
        })
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'检查云盘状态失败: {str(e)}'})

@app.route('/api/virtual/download/<file_md5>')
def virtual_download_file(file_md5):
    """下载虚拟网盘文件（智能检测云盘状态）"""
    try:
        cloud_type = request.args.get('cloudType', 'cloud189')
        parent_id = request.args.get('parentId', '-11')
        is_family = request.args.get('isFamily', 'false').lower() == 'true'
        
        # 获取文件信息
        file_info = virtual_cloud.get_file_info(file_md5)
        if not file_info:
            return jsonify({'success': False, 'message': '文件信息不存在'})
        
        # 检查云盘文件状态
        cloud_status = virtual_cloud.check_cloud_file_exists(file_md5, cloud_type, parent_id, is_family)
        
        if not cloud_status['exists']:
            # 文件在云盘中不存在，需要先上传
            return jsonify({
                'success': False, 
                'message': f'文件在云盘中不存在，需要先上传。{cloud_status["message"]}',
                'need_upload': True,
                'cloud_status': cloud_status
            })
        
        # 获取文件内容
        file_content = virtual_cloud.get_file_content(file_md5, cloud_type, parent_id, is_family)
        
        if not file_content:
            return jsonify({
                'success': False, 
                'message': '文件内容获取失败，可能需要重新上传',
                'need_upload': True
            })
        
        # 构建响应
        from urllib.parse import quote
        response = Response(file_content)
        response.headers['Content-Type'] = 'application/octet-stream'
        # 使用URL编码处理中文文件名，还原原始文件名
        encoded_filename = quote(file_info["original_name"], safe='')
        response.headers['Content-Disposition'] = f'attachment; filename*=UTF-8\'\'{encoded_filename}'
        response.headers['Content-Length'] = str(len(file_content))
        
        return response
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'下载失败: {str(e)}'})

@app.route('/api/virtual/upload_to_cloud', methods=['POST'])
def virtual_upload_to_cloud():
    """将虚拟网盘文件上传到云盘"""
    try:
        data = request.get_json()
        file_md5 = data.get('fileMd5')
        cloud_type = data.get('cloudType', 'cloud189')
        parent_id = data.get('parentId', '-11')
        is_family = data.get('isFamily', False)
        
        if not file_md5:
            return jsonify({'success': False, 'message': '缺少文件MD5'})
        
        result = virtual_cloud.upload_to_cloud(file_md5, cloud_type, parent_id, is_family)
        
        return jsonify(result)
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'上传到云盘失败: {str(e)}'})

@app.route('/api/virtual/delete/<file_md5>', methods=['DELETE'])
def virtual_delete_file(file_md5):
    """删除虚拟网盘文件"""
    try:
        delete_cache = request.args.get('deleteCache', 'true').lower() == 'true'
        delete_cloud = request.args.get('deleteCloud', 'false').lower() == 'true'
        
        result = virtual_cloud.delete_file(file_md5, delete_cache, delete_cloud)
        
        return jsonify(result)
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'删除文件失败: {str(e)}'})

@app.route('/api/virtual/statistics')
def virtual_get_statistics():
    """获取虚拟网盘统计信息"""
    try:
        stats = virtual_cloud.get_statistics()
        return jsonify({'success': True, 'statistics': stats})
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'获取统计信息失败: {str(e)}'})

@app.route('/api/virtual/cleanup', methods=['POST'])
def virtual_cleanup():
    """清理虚拟网盘缓存"""
    try:
        data = request.get_json() or {}
        max_age_days = data.get('maxAgeDays', 30)
        max_cache_size_mb = data.get('maxCacheSizeMb', 1024)
        
        result = virtual_cloud.cleanup(max_age_days, max_cache_size_mb)
        
        return jsonify({
            'success': True,
            'cleanup_result': result
        })
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'清理失败: {str(e)}'})

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)